LIBRARY ieee;
USE ieee.std_logic_1164.all;
                                                  --引入库和程序包，以此使用std_logic等数据类型

																  
																  
--std_logic_vector标准逻辑向量“1010” 读写顺序从左向右从高位到低位																  
--std_logic 标准逻辑‘0’，‘1’（“” ‘’ 固定语法，整数不加，字符‘’，字符串“”）																  
--STD标准逻辑取值‘0’‘1’‘X’（不定，赋值）‘U’（不定，初始）‘Z’（高阻）‘W’（弱信号不定）‘L’（弱信号0）‘H’（弱信号1）‘-’（不可能情况）														  

																  
--*****************实体部分*************************--
ENTITY Car_tracking IS                             --实体固定语法，‘Car_tracking’作为实体名，同时文件名要与其一致,该文件作为顶层文件则顶层文件名也与其一致
                                                  --GENERIC 是用于说明设计实体和其外部环境通信的对象，规定端口的大小、实体中子元件的数目、实体的延时特性
	GENERIC (												  --此处为实体说明部分
	
--时钟为50MHz，为了产生100Hz的PWM波，设置计数值为500000（相关计算：50*10^6  /100 =500000)

	cnt_meta : INTEGER := 500;    --计数预设值	500000/////////////////////////////////////////////////////////////Warning!!!!!
	 
--对应了停止、前进、左转、右转状态IN4到IN1的输出（in_motor的逻辑向量输出值预设）

	StopCar    : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "0000" ;  --（四口低电平）   	
	Forward    : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "0110" ;  --（同向正转）
	GoBack     : STD_LOGIC_VECTOR(3 DOWNTO 0) := "1001"  ;  --（同向反转）
	
	Left_Go_1   : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "0110" ; --（同向正转）
	Right_Go_1  : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "0110" ; --（同向正转）
		
	Left_GO_2  : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "1010" ;  --（一正一反）
	Right_GO_2 : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "0101" ;  --（一正一反）
	
	Left_GO_3  : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "0100" ;  --（一正一停）
	Right_GO_3 : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "0010" ;  --（一正一停）
	
	Turn_1_Y_Back : STD_LOGIC_VECTOR(0 TO 2)  := "101" ;  --从左到右第一位 0（未检测到黑线停止） 1（未检测到黑线后退）
	Turn_2_Y_Back : STD_LOGIC_VECTOR(0 TO 2)  := "110" ;  --从左到右第二，三位为 二进制下的1.2.3模式
	Turn_3_Y_Back : STD_LOGIC_VECTOR(0 TO 2)  := "111" ;  
	Turn_1_N_Back : STD_LOGIC_VECTOR(0 TO 2)  := "001" ;  
	Turn_2_N_Back : STD_LOGIC_VECTOR(0 TO 2)  := "010" ;
	Turn_3_N_Back : STD_LOGIC_VECTOR(0 TO 2)  := "011" 
	
	);
		
--*********转向的实现方法*********--


--1：Left_Go : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "1001" Right_Go : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "1001" （通过在前进的基础上，改变左右轮的转速实现）
--2：Left_Go : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "1010" Right_Go : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "0101"	 （通过两个轮子，一个正转一个反转实现）
--3：Left_Go : STD_LOGIC_VECTOR(3 DOWNTO 0)  := "1000"	 Right_Go : STD_LOGIC_VECTOR(3 DOWNTO 0) := "0001" （通过一个轮子转动一个轮子停止实现）


--******************输入输出端口**********************--
                                                       --端口 为信号类signal可省略
PORT (
	signal sys_clk : IN STD_LOGIC;                      --时钟信号（信号来源为确定的PIN_17产生） 
	signal sys_rst_n : IN STD_LOGIC;		                --复位信号	（信号来源为确定的PIN_90产生）		     
	
	signal infrared : IN STD_LOGIC_VECTOR(1 DOWNTO 0);  --红外信号（1左0右）左右      循迹模块 亮低电平无检测黑线，检测到黑线不亮高电平
	signal avoid : IN STD_LOGIC_VECTOR(0 TO 1);         --障碍物信号	
	
	signal mode : IN STD_LOGIC_VECTOR(0 TO 2);          --模式选择
 
	signal en_left  : OUT STD_LOGIC;						    --左轮使能（通过EN口‘10’实现）（作为PWM的输出接口）
	signal en_right : OUT STD_LOGIC;					       --右轮使能（通过EN口‘10’实现）（作为PWM的输出接口）
	signal in_motor : OUT STD_LOGIC_VECTOR(3 DOWNTO 0); --电机的四线接口（实际上也可以对电机的四个接口分别使用STD_LOGIC定义，优化代码，一线四口）
	
	signal OUT_HIGH : OUT STD_LOGIC_VECTOR(0 TO 1);     --恒定输出高电平
	signal OUT_LOW  : OUT STD_LOGIC_VECTOR(0 TO 1)      --恒定输出低电平（供模式切换使用）
	);
  
  END Car_tracking;
--实体部分定义结束--

  
--*******************结构体部分**********************--
                                                             --多个结构体时才需要使用configuration配置结构体间相关关系
ARCHITECTURE trans OF Car_tracking IS                         --architecture 结构名 of 实体名 is
                                                             --结构体说明部分，声明信号（定义语句用于对结构体内部所使用的信号、常数、数据类型和函数等进行定义。）
	SIGNAL cnt : INTEGER;                                     --integer为整数类型，数据输入时直接输入整数即可
	SIGNAL duty_left : INTEGER;
	SIGNAL duty_right : INTEGER;
                                                              --若未被声明则初次声明赋值语法为：signal duty_left ：integer ：= 1；（赋初值时）	

																				  
BEGIN 

--结构体内P1，P2，P3，同时运行，process内顺序执行

--************避障循迹程序A************--		

P1: PROCESS (sys_rst_n, infrared, avoid)      --接入的信号                   --并行v 语句 [进程名]:PROCESS(信号 1,信号 2,…)
												
BEGIN

	IF (sys_rst_n = '0') THEN                  --当按下复位键后开始执行语句（下降沿复位，由原理图得出）
			duty_right <= 0 ;                    --信号赋值语法使用 ***<=*** 
			duty_left <= 0;
	  ELSE
	
			IF (avoid = "11") THEN   --如果没有检测到障碍物则执行循迹
		
				CASE mode IS
		
							WHEN  (Turn_1_Y_Back OR Turn_1_N_Back)  =>  --转弯模式方案一
	
									IF (infrared ="00") THEN  			  --当左右均无黑线时
				
												IF (mode = Turn_1_Y_Back) THEN  --进行后退
				
														in_motor <= GoBack ;
														duty_left <= 30;
														duty_right <= 30;
				
												ELSIF (mode = Turn_1_N_Back) THEN  --执行停止
			
														in_motor <= StopCar;
					
												END IF;	
				
									ELSIF (infrared ="01") THEN				  --左无，右有，执行右转
											in_motor <= Right_Go_1; 
											duty_left <= 30;      --PWM占空比（取值0--100）（数值越大，转速越高）
											duty_right <= 30;
					
		
									ELSIF (infrared ="10") THEN				  --左有，右无，执行左转
											in_motor <= Left_Go_1;
											duty_left <= 60;
											duty_right <= 30;
		
									ELSE				               --左右均有黑线时，执行前进             
											in_motor <= Forward;
											duty_left <= 60;
											duty_right <= 60;
			
									END IF;
				
							WHEN  (Turn_2_Y_Back OR Turn_2_N_Back)  =>   --转弯模式方案二
  
		
									IF (infrared = "00") THEN  				  --当左右均无黑线时
				
													IF (mode = Turn_2_Y_Back) THEN --执行后退
															in_motor <= GoBack ;
															duty_left <= 30;
															duty_right <= 30;
					
												ELSIF (mode = Turn_2_N_Back) THEN --执行停止
			
														in_motor <= StopCar;
														
												END IF;
						
									ELSIF (infrared = "01") THEN			--左无，右有，执行右转
											in_motor <= Right_Go_2;
											duty_left <= 30;       
											duty_right <= 30;
		
									ELSIF (infrared = "10") THEN			--左有，右无，执行左转
											in_motor <= Left_Go_2;
											duty_left <= 30;
											duty_right <= 30;
		
									ELSE				                    --左右均有黑线时，执行前进              
											in_motor <= Forward;
											duty_left <= 60;
											duty_right <= 60;
					
									END IF;
			
					
						WHEN OTHERS =>                           --转弯模式方案三
		
									IF (infrared = "00") THEN  				  --当左右均无黑线时
				
													IF (mode = Turn_3_Y_Back) THEN --执行后退
				
															in_motor <= GoBack ;
															duty_left <= 30;
															duty_right <= 30;
					
												ELSIF (mode = Turn_3_N_Back) THEN  --执行停止
			
														in_motor <= StopCar;
				
												END IF;
						
									ELSIF (infrared = "01") THEN				--左无，右有，执行右转			
											in_motor <= Right_Go_3;			
											duty_left <= 30;       
			
		
									ELSIF (infrared = "10") THEN				  --左有，右无，执行左转
											in_motor <= Left_Go_3;		
											duty_right <= 30;
		
									ELSE				  
											in_motor <= Forward;              --左右均有黑线时，执行前进    
											duty_left <= 60;
											duty_right <= 60;
					
									END IF;
				
				 END CASE;
			ELSE 	
			           in_motor <= StopCar;	  --检测到障碍物停止
		END IF;	
	 END IF;		
END PROCESS P1 ;

	
--***************计数器***************--	
P3: PROCESS (sys_clk, sys_rst_n)  --接入信号

BEGIN

--*********************	
	OUT_HIGH <= "11" ;  --固定输出高电平
	OUT_LOW  <= "00" ;  --固定输出低电平
--*********************
	
	       IF (sys_rst_n = '0') THEN    --当复位键按下后
			     cnt <= 0;				  --为‘计数’赋值整数0
		
		   ELSIF (sys_clk'EVENT AND sys_clk = '1') THEN   --当clk信号遭遇上升沿则...（开始计数）
    --   event事件 即 信号是否发生跳变   跳变后信号变为高电平
        --			（发生返回ture，反之假）
				
			IF (cnt = cnt_meta) THEN  --判断‘计数’值是否与预设计数次数相同
				cnt <= 0;				  --相同则赋值0，重新开始计数
			ELSE
				cnt <= cnt + 1;		  --不相同则‘计数’值+1
				
		END IF;
	END IF;		
END PROCESS P3 ;
	
--**************PWM功能实现*************--	
P4: PROCESS (sys_clk, sys_rst_n)  --接入信号
	
BEGIN
	
	  IF (sys_rst_n = '0') THEN  --如果复位键按下
				en_left <= '0';     --按动复位键时，强制停止
				en_right <= '0';    --（此初值可以任意，当开始运行循迹程序后，会自动赋予相应的值）
				
		  ELSIF (sys_clk'EVENT AND sys_clk = '1') THEN  --当clk信号的上升沿则...（开始计数）
			
--左轮PWM				
		     IF (cnt >= (cnt_meta / 100) * duty_left) THEN --当‘计数’值 大于等于 预设PWM占空数时（公式只为优化代码输入时值位于0-100）
				   en_left <= '0';
		   ELSE
				   en_left <= '1';  
		      END IF;
		
           --即在计数器（0—0.5M）计数大周期内，在cnt（0——预设pwm占空数）的时间内高电平，在cnt大于预设值时低电平	，以此实现PWM脉宽调制
	
--右轮PWM	
		     IF (cnt >= (cnt_meta / 100) * duty_right) THEN	--当‘计数’值 大于等于 预设PWM占空数时（公式只为优化代码输入时值位于0-100）
				   en_right <= '0';
		    ELSE
				   en_right <= '1';
				
				END IF;
			END IF;
END PROCESS P4 ;

END trans;
--********结构体定义结束**********--
